home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 June: Reference Library / Dev.CD Jun 96 RL / Dev.CD Jun 96 RL.toast / What's New? / Development Kits / Apple Game Sprockets DR1 / Examples / GlyphaIII / G3Utilities.c < prev    next >
Encoding:
Text File  |  1996-04-24  |  17.3 KB  |  518 lines  |  [TEXT/MPCC]

  1.  
  2. //============================================================================
  3. //----------------------------------------------------------------------------
  4. //                                    Utilities.c
  5. //----------------------------------------------------------------------------
  6. //============================================================================
  7.  
  8. // These functions are sort of universal utility functions.  They aren't specific…
  9. // to Glypha per se.  I use these (and others) in many, many games.  Many of them…
  10. // as well are useful for any app you might write for the Mac.
  11.  
  12. #include "G3Externs.h"
  13.  
  14.  
  15. #define kActive                        0
  16. #define kInactive                    255
  17.  
  18.  
  19. GDHandle    thisGDevice;
  20. long        tickNext;
  21.  
  22.  
  23. //==============================================================  Functions
  24. //--------------------------------------------------------------  RandomInt
  25.  
  26. // Takes a short (range) and returns a random number from zero to range - 1.
  27.  
  28. short RandomInt (short range)
  29. {
  30.     register long    rawResult;
  31.     
  32.     rawResult = Random();
  33.     if (rawResult < 0L)
  34.         rawResult *= -1L;
  35.     rawResult = (rawResult * (long)range) / 32768L;
  36.     
  37.     return ((short)rawResult);
  38. }
  39.  
  40. //--------------------------------------------------------------  RedAlert
  41.  
  42. // Generic error function.  This is called when there is no hope of recovering
  43. // from the error.  A simple alert is brought up and the text passed in (theStr)
  44. // is displayed.  When the user clicks the Okay button, we quit to the Finder.
  45.  
  46. void RedAlert (StringPtr theStr)
  47. {
  48.     #define        kRedAlertID        128
  49.     short        whoCares;
  50.  
  51. #if GENERATINGPOWERPC
  52.     // make sure we are at full color
  53.     FadeDisplayGamma( NULL, 100, NULL );
  54.     
  55.     if( gTheDisplay )
  56.     {
  57.         SetDisplayPlayState( gTheDisplay, kDisplayPlayStateInactive );
  58.         DisposeDisplay( gTheDisplay );
  59.     }
  60.     
  61. #endif    
  62.  
  63.     ParamText(theStr, "\p", "\p", "\p");        // Replace ^0 in alert with error mssg.
  64.     whoCares = Alert(kRedAlertID, 0L);            // Bring up alert.
  65.     ExitToShell();                                // Quit to Finder.
  66. }
  67.  
  68. //--------------------------------------------------------------  FindOurDevice
  69.  
  70. // Get a handle to the MainDevice (monitor with the Menubar).
  71.  
  72. void FindOurDevice (void)
  73. {
  74.     thisGDevice = GetMainDevice();
  75.     if (thisGDevice == 0L)                        // If a nil handle is returned...
  76.         RedAlert("\pCouldn't Find Our Device");    // call our universal error alert.
  77. }
  78.  
  79. //--------------------------------------------------------------  LoadGraphic
  80.  
  81. // Handy function that loads a PICT graphic, get's its bounds and draws it.
  82. // The port drawn to is assumed the current port.  No scaling is done.
  83.  
  84. void LoadGraphic (short resID)
  85. {
  86.     Rect        bounds;
  87.     PicHandle    thePicture;
  88.     
  89.     thePicture = GetPicture(resID);                // Load graphic from resource fork.
  90.     if (thePicture == 0L)                        // Check to see if nil (did it load?)
  91.         RedAlert("\pA Graphic Couldn't Be Loaded");
  92.     
  93.     HLock((Handle)thePicture);                    // If we made it this far, lock handle.
  94.     bounds = (*thePicture)->picFrame;            // Get a copy of the picture's bounds.
  95.     HUnlock((Handle)thePicture);                // We can unlock the picture now.
  96.     OffsetRect(&bounds, -bounds.left, -bounds.top);    // Offset bounds rect to (0, 0).
  97.     DrawPicture(thePicture, &bounds);            // Draw picture to current port.
  98.     
  99.     ReleaseResource((Handle)thePicture);        // Dispose of picture from heap.
  100. }
  101.  
  102. //--------------------------------------------------------------  CreateOffScreenPixMap
  103.  
  104. // Handles the creation of an offscreen pixmap.  Depth is assumed to be that of the…
  105. // current gDevice.  If the allocation fails (low memory, etc.) we quit to Finder.
  106.  
  107. void CreateOffScreenPixMap (Rect *theRect, CGrafPtr *offScreen)
  108. {
  109.     CTabHandle    thisColorTable;
  110.     GDHandle    oldDevice;
  111.     CGrafPtr    newCGrafPtr;
  112.     Ptr            theseBits;
  113.     long        sizeOfOff, offRowBytes;
  114.     OSErr        theErr;
  115.     short        thisDepth;
  116.     
  117.     oldDevice = GetGDevice();
  118.     SetGDevice(thisGDevice);
  119.     newCGrafPtr = 0L;
  120.     newCGrafPtr = (CGrafPtr)NewPtrClear(sizeof(CGrafPort));
  121.     if (newCGrafPtr != 0L)
  122.     {
  123.         OpenCPort(newCGrafPtr);
  124.         thisDepth = (**(*newCGrafPtr).portPixMap).pixelSize;
  125.         offRowBytes = ((((long)thisDepth * 
  126.                 (long)(theRect->right - theRect->left)) + 15L) >> 4L) << 1L;
  127.         sizeOfOff = (long)(theRect->bottom - theRect->top) * offRowBytes;
  128.         OffsetRect(theRect, -theRect->left, -theRect->top);
  129.         theseBits = NewPtr(sizeOfOff);
  130.         if (theseBits != 0L)
  131.         {
  132.             (**(*newCGrafPtr).portPixMap).baseAddr = theseBits;
  133.             (**(*newCGrafPtr).portPixMap).rowBytes = (short)offRowBytes + 0x8000;
  134.             (**(*newCGrafPtr).portPixMap).bounds = *theRect;
  135.             thisColorTable = (**(**thisGDevice).gdPMap).pmTable;
  136.             theErr = HandToHand((Handle *)&thisColorTable);
  137.             (**(*newCGrafPtr).portPixMap).pmTable = thisColorTable;
  138.             ClipRect(theRect);
  139.             RectRgn(newCGrafPtr->visRgn, theRect);
  140.             ForeColor(blackColor);
  141.             BackColor(whiteColor);
  142.             EraseRect(theRect);
  143.         }
  144.         else
  145.         {
  146.             CloseCPort(newCGrafPtr);        
  147.             DisposePtr((Ptr)newCGrafPtr);
  148.             newCGrafPtr = 0L;
  149.             RedAlert("\pCouldn't Allocate Enough Memory");
  150.         }
  151.     }
  152.     else
  153.         RedAlert("\pCouldn't Allocate Enough Memory");
  154.     
  155.     *offScreen = newCGrafPtr;
  156.     SetGDevice(oldDevice);
  157. }
  158.  
  159. //--------------------------------------------------------------  CreateOffScreenBitMap
  160.  
  161. // Creates an offscreen bitmap.  Depth is of course 1 (b & w).  If this function…
  162. // fails to create the bitmap, we post an alert and quit to the Finder.
  163.  
  164. void CreateOffScreenBitMap (Rect *theRect, GrafPtr *offScreen)
  165. {
  166.     GrafPtr        theBWPort;
  167.     BitMap        theBitMap;    
  168.     long        theRowBytes;
  169.     
  170.     theBWPort = (GrafPtr)(NewPtr(sizeof(GrafPort)));
  171.     OpenPort(theBWPort);
  172.     theRowBytes = (long)((theRect->right - theRect->left + 15L) / 16L) * 2L;
  173.     theBitMap.rowBytes = (short)theRowBytes;
  174.     theBitMap.baseAddr = NewPtr((long)theBitMap.rowBytes * 
  175.         (theRect->bottom - theRect->top));
  176.     if (theBitMap.baseAddr == 0L)
  177.         RedAlert("\pCouldn't Create Bitmaps");
  178.     theBitMap.bounds = *theRect;
  179.     if (MemError() != noErr)
  180.         RedAlert("\pCouldn't Create Bitmaps");
  181.     SetPortBits(&theBitMap);
  182.     ClipRect(theRect);
  183.     RectRgn(theBWPort->visRgn, theRect);
  184.     EraseRect(theRect);
  185.     *offScreen = theBWPort;
  186. }
  187.  
  188. //--------------------------------------------------------------  ZeroRectCorner
  189.  
  190. // Offset rect to (0, 0).  This means the upper left corner of the rect is 
  191. // moved to the origin - to (0, 0) - to the upperleft corner of the port.
  192.  
  193. void ZeroRectCorner (Rect *theRect)
  194. {
  195.     theRect->right -= theRect->left;    // Move right edge by amount of left.
  196.     theRect->bottom -= theRect->top;    // Move bottom edge by amount of top.
  197.     theRect->left = 0;                    // Can now set left to zero.
  198.     theRect->top = 0;                    // Can set top edge to zero as well.
  199. }
  200.  
  201. //--------------------------------------------------------------  FlashShort
  202.  
  203. // This is a simple debugging function that will display the short passed to it…
  204. // in the upper left corner of the screen.  It's a handy way to watch the value…
  205. // of a variable while the program is running.
  206.  
  207. void FlashShort (short theValue)
  208. {
  209.     GrafPtr            wasPort, tempPort;
  210.     Str255            tempStr;
  211.     Rect            tempRect;
  212.     
  213.     GetPort(&wasPort);                        // Remember old grafPort.
  214.     
  215.     tempPort = (GrafPtr)NewPtrClear(sizeof(GrafPort));
  216.     OpenPort(tempPort);                        // Create a new empty port.
  217.     
  218.     NumToString((long)theValue, tempStr);    // Convert value passed in to a string.
  219.     MoveTo(20, 40);                            // Move the pen to the upperleft corner.
  220.     SetRect(&tempRect, 18, 20, 122, 42);    // Create a rect up there as well.
  221.     EraseRect(&tempRect);                    // Erase the rect (to make a white hole).
  222.     DrawString(tempStr);                    // And draw our text into that hole.
  223.     
  224.     ClosePort(tempPort);                    // Get rid of out temp port.
  225.     SetPort((GrafPtr)wasPort);                // And set port back to the old one.
  226. }
  227.  
  228. //--------------------------------------------------------------  LogNextTick
  229.  
  230. // Simple function to set a global (tickNext) to the current TickCount() plus…
  231. // some offset.  We'll then wait for TickCount() to exceed that global.  We use…
  232. // this function and the function below to regulate animation speeds (remember…
  233. // your game may be run on a slow Mac or a fast one - we need a way to keep the…
  234. // motion consistent.  I love when the comments are longer than the function.
  235. // (Not really.)
  236.  
  237. void LogNextTick (long howMany)
  238. {
  239.     tickNext = TickCount() + howMany;        // Get machine's TickCount() and add to it.
  240. }
  241.  
  242. //--------------------------------------------------------------  WaitForNextTick
  243.  
  244. // This is the companion function to the above function (LogNextTick()).
  245. // We do nothing but loop until TickCount() catches up with (or passes) our…
  246. // global variable tickNext.
  247.  
  248. void WaitForNextTick (void)
  249. {
  250.     do
  251.     {
  252.     }
  253.     while (TickCount() < tickNext);            // Loop until TickCount() catches up.
  254. }
  255.  
  256. //--------------------------------------------------------------  TrapExists  
  257.  
  258. // A nice "test function" that test for the existence of some ToolBox trap.
  259. // Returns TRUE if the function exists, FALSE if it doesn't.
  260.  
  261. Boolean TrapExists (short trapNumber)
  262. {
  263.     #define        kUnimpTrap        0x9F
  264.     
  265.                 // Test trap number against unimplemented trap number.
  266.     return ((NGetTrapAddress(trapNumber, ToolTrap) !=
  267.             NGetTrapAddress(kUnimpTrap, ToolTrap)));
  268. }
  269.  
  270. //--------------------------------------------------------------  DoWeHaveGestalt  
  271.  
  272. // This function specifically tests for the availablity of the Gestalt() function.
  273. // It returns TRUE if Gestalt() exists, FALSE if it doesn't.
  274.  
  275. Boolean DoWeHaveGestalt (void)
  276. {
  277.     #define        kGestaltTrap    0xAD
  278.     
  279.                 // Call above function (TrapExists()) with the Gestalt() trap number.
  280.     return (TrapExists(kGestaltTrap));
  281. }
  282.  
  283. //--------------------------------------------------------------  CenterAlert
  284.  
  285. // Handy function to center any alert within the main monitor.
  286.  
  287. void CenterAlert (short alertID)
  288. {
  289.     AlertTHndl    alertHandle;
  290.     Rect        theScreen, alertRect;
  291.     short        horiOff, vertOff;
  292.     Byte        wasState;
  293.     
  294.     theScreen = qd.screenBits.bounds;        // Get main monitor's bounds.
  295.     theScreen.top += LMGetMBarHeight();        // Account for menubar height.
  296.                                             // Get handle to alert resource.
  297.     alertHandle = (AlertTHndl)GetResource('ALRT', alertID);
  298.     if (alertHandle != 0L)                    // Make sure we got it!
  299.     {                                        // Remember its "state" (locked, etc.)
  300.         wasState = HGetState((Handle)alertHandle);
  301.         HLock((Handle)alertHandle);            // We'll lock it.
  302.                                             // Get a copy of it's bounds and zero.
  303.         alertRect = (**alertHandle).boundsRect;
  304.         OffsetRect(&alertRect, -alertRect.left, -alertRect.top);
  305.                                             // Calculate offsets for centering bounds.
  306.         horiOff = ((theScreen.right - theScreen.left) - alertRect.right) / 2;    
  307.         vertOff = ((theScreen.bottom - theScreen.top) - alertRect.bottom) / 3;
  308.                                             // And offset the bounds copy.
  309.         OffsetRect(&alertRect, horiOff, vertOff + LMGetMBarHeight());
  310.                                             // Set alerts bounds to our centered rect.
  311.         (**alertHandle).boundsRect = alertRect;
  312.         HSetState((Handle)alertHandle, wasState);
  313.     }
  314. }
  315.  
  316. //--------------------------------------------------------------  RectWide
  317.  
  318. // Handy function for returning the absolute width of a rectangle.
  319.  
  320. short RectWide (Rect *theRect)
  321. {
  322.     return (theRect->right - theRect->left);
  323. }
  324.  
  325. //--------------------------------------------------------------  RectTall
  326.  
  327. // Handy function for returning the absolute height of a rectangle.
  328.  
  329. short RectTall (Rect *theRect)
  330. {
  331.     return (theRect->bottom - theRect->top);
  332. }
  333.  
  334. //--------------------------------------------------------------  CenterRectInRect
  335.  
  336. // Nice utility function that takes two rectangles and centers the first…
  337. // rectangle within the second.
  338.  
  339. void CenterRectInRect (Rect *rectA, Rect *rectB)
  340. {
  341.     short    widthA, tallA;
  342.     
  343.     widthA = RectWide(rectA);                // Get width of 1st rect.
  344.     tallA = RectTall(rectA);                // Get height of 1st rect.
  345.                                             // Do the math (center horizontally).
  346.     rectA->left = rectB->left + (RectWide(rectB) - widthA) / 2;
  347.     rectA->right = rectA->left + widthA;
  348.                                             // Do the math (center vertically).
  349.     rectA->top = rectB->top + (RectTall(rectB) - tallA) / 2;
  350.     rectA->bottom = rectA->top + tallA;
  351. }
  352.  
  353. //--------------------------------------------------------------  PasStringCopy
  354.  
  355. // This is a nice function that helps to free you from dealing with C strings.
  356. // It takes one Pascal-style string and copies it to a second.
  357.  
  358. void PasStringCopy (StringPtr p1, StringPtr p2)
  359. {
  360.     register short        stringLength;
  361.     
  362.     stringLength = *p2++ = *p1++;    // Get 1st string's length.
  363.     while (--stringLength >= 0)        // Loop through each character in 1st string.
  364.         *p2++ = *p1++;                // And copy to 2nd string.
  365. }
  366.  
  367. //--------------------------------------------------------------  CenterDialog
  368.  
  369. // Like CenterAlert(), this function centers a Dialog on the main monitor.
  370.  
  371. void CenterDialog (short dialogID)
  372. {
  373.     DialogTHndl    dlogHandle;
  374.     Rect        theScreen, dlogBounds;
  375.     short        hPos, vPos;
  376.     Byte        wasState;
  377.     
  378.     theScreen = qd.screenBits.bounds;            // Get main monitor's bounds.
  379.     theScreen.top += LMGetMBarHeight();            // Add menuBar's height.
  380.                                                 // Load up dialog from resource.
  381.     dlogHandle = (DialogTHndl)GetResource('DLOG', dialogID);
  382.     if (dlogHandle != 0L)                        // If it loaded....!
  383.     {                                            // Remember handle state.
  384.         wasState = HGetState((Handle)dlogHandle);
  385.         HLock((Handle)dlogHandle);                // We're going to lock it.
  386.                                                 // Get a copy of the dialog's bounds.
  387.         dlogBounds = (**dlogHandle).boundsRect;
  388.         OffsetRect(&dlogBounds, -dlogBounds.left, -dlogBounds.top);
  389.                                                 // Calculate how much to offset.
  390.         hPos = ((theScreen.right - theScreen.left) - dlogBounds.right) / 2;
  391.         vPos = ((theScreen.bottom - theScreen.top) - dlogBounds.bottom) / 3;
  392.                                                 // Offset ourt copy of the bounds.
  393.         OffsetRect(&dlogBounds, hPos, vPos + LMGetMBarHeight());
  394.                                                 // Set dlg's bounds to centered rect.
  395.         (**dlogHandle).boundsRect = dlogBounds;
  396.         HSetState((Handle)dlogHandle, wasState);// Restore handle's state.
  397.     }
  398. }
  399.  
  400. //--------------------------------------------------------------  DrawDefaultButton
  401.  
  402. // A nice dialog function.  This draws the bold default outline around…
  403. // item #1 in the dialog passed in.
  404.  
  405. void DrawDefaultButton (DialogPtr theDialog)
  406. {
  407.     Rect        itemRect;
  408.     Handle        itemHandle;
  409.     short        itemType;
  410.                                         // Get at the item's bounds.
  411.     GetDItem(theDialog, 1, &itemType, &itemHandle, &itemRect);
  412.     InsetRect(&itemRect, -4, -4);        // Inset (outset?) bounds by -4 pixels.
  413.     PenSize(3, 3);                        // Set the pen 3 pixels thick.
  414.     FrameRoundRect(&itemRect, 16, 16);    // Draw the button outline.
  415.     PenNormal();                        // And restore pen to 1 pixel thick.
  416. }
  417.  
  418. //--------------------------------------------------------------  PasStringCopyNum
  419.  
  420. // Another function to keep you from using C strings.  This one copies only a…
  421. // certain number of characters from one Pascal-style string to a second.
  422.  
  423. void PasStringCopyNum (StringPtr p1, StringPtr p2, short charsToCopy)
  424. {
  425.     short        i;
  426.     
  427.     if (charsToCopy > *p1)        // If trying to copy more chars than there are…
  428.         charsToCopy = *p1;        // Reduce the number of chars to copy to this size
  429.     
  430.     *p2 = charsToCopy;            // Set 2nd string's length to charsToCopy.
  431.     
  432.     *p2++;                        // Point to first character in 2nd string.
  433.     *p1++;                        // Point to first character in 1st string.
  434.     
  435.     for (i = 0; i < charsToCopy; i++)
  436.         *p2++ = *p1++;            // Copy the specified number of chars over.
  437. }
  438.  
  439. //--------------------------------------------------------------  GetDialogString
  440.  
  441. // Handy dialog function that returns a dialog item string.  This will be…
  442. // especially handy for getting the high score name the player enters.
  443.  
  444. void GetDialogString (DialogPtr theDialog, short item, StringPtr theString)
  445. {
  446.     Rect        itemRect;
  447.     Handle        itemHandle;
  448.     short        itemType;
  449.                                         // Get handle to dialog item.
  450.     GetDItem(theDialog, item, &itemType, &itemHandle, &itemRect);
  451.     GetIText(itemHandle, theString);    // Extract text from item handle.
  452. }
  453.  
  454. //--------------------------------------------------------------  SetDialogString
  455.  
  456. // Like the above function, but this one sets a dialog items string to whatever…
  457. // you pass in.  We'll use this to set a default high score name.
  458.  
  459. void SetDialogString (DialogPtr theDialog, short item, StringPtr theString)
  460. {
  461.     Rect        itemRect;
  462.     Handle        itemHandle;
  463.     short        itemType;
  464.                                         // Get handle to dialog item.
  465.     GetDItem(theDialog, item, &itemType, &itemHandle, &itemRect);
  466.     SetIText(itemHandle, theString);    // Set the items text to theString.
  467. }
  468.  
  469. //--------------------------------------------------------------  SetDialogNumToStr
  470.  
  471. // This one is like SetDialogString() above, but it takes a number (long)…
  472. // instead of a string (the function will convert the long to a string for us).
  473.  
  474. void SetDialogNumToStr (DialogPtr theDialog, short item, long theNumber)
  475. {
  476.     Str255        theString;
  477.     Rect        itemRect;
  478.     Handle        itemHandle;
  479.     short        itemType;
  480.     
  481.     NumToString(theNumber, theString);    // Convert long to a string.
  482.     GetDItem(theDialog, item, &itemType, &itemHandle, &itemRect);
  483.     SetIText(itemHandle, theString);    // Set the item's text to this number/string.
  484. }
  485.  
  486. //--------------------------------------------------------------  GetDialogNumFromStr
  487.  
  488. // This one is like GetDialogString() above, but returns a long (number)…
  489. // instead of a string (it does this by converting the string to a long).
  490.  
  491. void GetDialogNumFromStr (DialogPtr theDialog, short item, long *theNumber)
  492. {
  493.     Str255        theString;
  494.     Rect        itemRect;
  495.     Handle        itemHandle;
  496.     short        itemType;
  497.                                         // Get a handle to the dialog item.
  498.     GetDItem(theDialog, item, &itemType, &itemHandle, &itemRect);
  499.     GetIText(itemHandle, theString);    // Get the item's text.
  500.     StringToNum(theString, theNumber);    // Convert the text to a long.
  501. }
  502.  
  503. //--------------------------------------------------------------  DisableControl
  504.  
  505. // Another dialog utility for "graying out" buttons or other controls in a dialog.
  506.  
  507. void DisableControl (DialogPtr theDialog, short whichItem)
  508. {
  509.     Rect        iRect;
  510.     Handle        iHandle;
  511.     short        iType;
  512.                                         // Get a handle to the dialog item.
  513.     GetDItem(theDialog, whichItem, &iType, &iHandle, &iRect);
  514.                                         // Set it's "hilite state" to "grayed out".
  515.     HiliteControl((ControlHandle)iHandle, kInactive);
  516. }
  517.  
  518.